package com.syu.loopcure.compensator;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.syu.loopcure.common.constants.LoopCoreGlobalConstant;
import com.syu.loopcure.compensator.dto.CompensatorDTO;
import com.syu.loopcure.compensator.enums.LogMsgEnum;
import com.syu.loopcure.compensator.enums.NumberEnum;
import com.syu.loopcure.compensator.enums.StatusEnum;
import com.syu.loopcure.compensator.interfaces.ICompensator;
import com.syu.loopcure.compensator.model.CompensatorInfoModel;
import org.springframework.util.StringUtils;

import javax.annotation.Nonnull;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * ClassName: LoopCureCompensator <br/>
 * Function: 补偿入口 <br/>
 * date: 2020年8月11日 上午10:49:39 <br/>
 *
 * @author zhucun
 * @since JDK 1.8
 */
public class LoopCureCompensator {

    private ICompensator compensator;

    /**
     *
     * analysisParamValues:解析参数值. <br/>
     *
     * @param callableMethod 函数
     * @param methodParamValues 参数值
     * @return Object[]
     * @since JDK 1.8
     * @author zhucun
     * @date 2020年8月11日 上午11:44:45
     * @modifier zhucun
     * @modifyDate 2020年8月11日 上午11:44:45
     */
    private Object[] analysisParamValues(Method callableMethod, String methodParamValues) {
        // 参数值集合
        List<String> methodparamValueObj = JSONObject.parseArray(methodParamValues, String.class);
        // 参数类型集合
        Type[] methodParamTypes = callableMethod.getGenericParameterTypes();
        Object[] paramValueObj = new Object[methodParamTypes.length];
        for (int i = 0; i < methodparamValueObj.size(); i++) {
            String paramValue = methodparamValueObj.get(i);
            // 参数值为空
            if (LoopCoreGlobalConstant.NULL_STR.equalsIgnoreCase(paramValue)) {
                paramValueObj[i] = null;
                continue;
            }
            Type paramType = methodParamTypes[i];
            // 参数类型为String类型
            if (String.class == paramType) {
                paramValueObj[i] = paramValue;
                continue;
            }
            // 参数类型为集合时
            if (List.class == paramType) {
                paramValueObj[i] = JSONObject.parseObject(paramValue, List.class);
                continue;
            }
            // 参数类型为泛型时
            if (paramType instanceof ParameterizedType) {
                // 带泛型的List
                ParameterizedTypeImpl genericityType = (ParameterizedTypeImpl) paramType;
                if (List.class == genericityType.getRawType()) {
                    // 获取泛型参数
                    ParameterizedType parameterizedType = (ParameterizedType) paramType;
                    // 获取泛型参数对象
                    Class<?> paramClass = (Class<?>) parameterizedType.getActualTypeArguments()[0];
                    paramValueObj[i] = JSONObject.parseArray(paramValue, paramClass);
                    continue;
                }
            }
            // 带泛型的其他集合类型,POJO类型，直接解析对象
            paramValueObj[i] = JSONObject.parseObject(paramValue, paramType, Feature.OrderedField);
        }
        return paramValueObj;
    }

    /**
     *
     * Creates a new instance of LoopCureCompensator.
     *
     */
    public LoopCureCompensator() {

    }

    /**
     *
     * newBuilder:构建实体静态方法. <br/>
     *
     * @return  {@link LoopCureCompensator}
     * @since JDK 1.8
     * @author zhucun
     * @date 2020年8月11日 下午5:32:42
     * @modifier zhucun
     * @modifyDate 2020年8月11日 下午5:32:42
     */
    public static LoopCureCompensator newBuilder() {
        return new LoopCureCompensator();
    }

    /**
     *
     * setCompensatorInterface:设置补偿接口. <br/>
     *
     * @param compensator {@link ICompensator}
     * @return  {@link LoopCureCompensator}
     * @since JDK 1.8
     * @author zhucun
     * @date 2020年8月11日 下午5:27:42
     * @modifier zhucun
     * @modifyDate 2020年8月11日 下午5:27:42
     */
    public LoopCureCompensator setCompensatorInterface(@Nonnull ICompensator compensator) {

        this.compensator = compensator;
        return this;
    }

    /**
     *
     * analysisMethod:解析待执行的方法&入参. <br/>
     *
     * @param model
     *            {@link CompensatorInfoModel}
     * @return {@link CompensatorDTO}
     * @since JDK 1.8
     * @author zhucun
     * @date 2020年8月11日 下午2:24:31
     * @modifier zhucun
     * @modifyDate 2020年8月11日 下午2:24:31
     */
    public CompensatorDTO analysisMethod(CompensatorInfoModel model) {
        // 类名
        String className = model.getClassName();
        // 方法名
        String methodName = model.getMethodName();
        // 参数值
        String methodParamValues = model.getMethodParamValues();
        // 通过反射获取class，获取待执行的method
        Method callableMethod = null;
        try {
            // 类
            Class<?> callableClass = Class.forName(className);
            // 方法
            Method[] allMethods = callableClass.getMethods();
            for (Method method : allMethods) {
                if (method.getName().equals(methodName)) {
                    callableMethod = method;
                    break;
                }
            }
            // 方法是否存在
            if (null == callableMethod) {
                throw new RuntimeException(LogMsgEnum.toLogStr(LogMsgEnum.METHOD_NOT_FIND.getCode(), methodName));
            }
            // 存在参数时，解析参数
            Object[] paramValueObj = null;
            if (!StringUtils.isEmpty(methodParamValues)) {
                paramValueObj = analysisParamValues(callableMethod, methodParamValues);
            }
            // 允许访问权限
            callableMethod.setAccessible(Boolean.TRUE);
            // 反射调用方法
            Annotation[] methodAnnotations = callableMethod.getDeclaredAnnotations();
            // 异步&同步标志
            boolean asyncFlag = Boolean.FALSE;
            if (methodAnnotations.length > 0) {
                for (Annotation annotation : methodAnnotations) {
                    if (LoopCoreGlobalConstant.SPRING_ASYNC_CLASS_NAME
                            .equalsIgnoreCase(annotation.annotationType().getTypeName())) {
                        asyncFlag = Boolean.TRUE;
                        break;
                    }
                }
            }
            return new CompensatorDTO(callableClass, callableMethod, paramValueObj, asyncFlag);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            if(null != callableMethod) {
                callableMethod.setAccessible(Boolean.FALSE);
            }
        }

    }

    /**
     *
     * doCompensator:执行补偿. <br/>
     *
     * @return ture/false
     * @since JDK 1.8
     * @author zhucun
     * @date 2020年8月13日 下午7:39:31
     * @modifier zhucun
     * @modifyDate 2020年8月13日 下午7:39:31
     */
    public boolean doCompensator() {

        // 补偿model不能为空
        if (null == compensator) {
            throw new NullPointerException(LogMsgEnum.toLogStr(LogMsgEnum.INTERFACE_NULL.getCode(), "ICompensator"));
        }
        try {
            // 得到补偿model对象
            CompensatorInfoModel compensatorInfoModel = compensator.obtainCompensatorInfo();
            // 解析补偿model对象，获取待执行的方法&入参
            CompensatorDTO compensatorDto = this.analysisMethod(compensatorInfoModel);
            // 方法所在类
            Class<?> callableClass = compensatorDto.getCallableClass();
            // 方法
            Method callableMethod = compensatorDto.getCallableMethod();
            // 方法入参
            Object[] paramValueObj = compensatorDto.getParamValueObj();
            // 异步同步标志
            Boolean asyncFlag = compensatorDto.getAsyncFlag();

            // 执行成功时更新状态，执行异常时由AOP捕获，不做处理
            compensatorInfoModel.setModifyTime(new Date());
            // 方法执行前更新数据，譬如执行开始时间等
            compensatorInfoModel.setRetryTimes(compensatorInfoModel.getRetryTimes() + NumberEnum.ONE.getNumber());
            compensatorInfoModel.setRetryStartTime(new Date());
            compensatorInfoModel.setStatus(StatusEnum.DOING_COMPENSATOR.getCode());
            compensator.updateInfoBeforeExecuteMethodByMd5Code(compensatorInfoModel);
            // 非异步方法
            if(!asyncFlag) {

                // 执行方法
                callableMethod.invoke(compensator.getBean(callableClass), paramValueObj);

                // 执行成功后 更新
                compensatorInfoModel.setRetryEndTime(new Date());
                compensatorInfoModel.setStatus(StatusEnum.SUCCESS_COMPENSATOR.getCode());
                compensatorInfoModel.setSuccessMsg(StatusEnum.SUCCESS_COMPENSATOR.getMsg());
                compensator.successUpdateInfoByMd5Code(compensatorInfoModel);
                return Boolean.TRUE;
            }
            // 异步方法
            @SuppressWarnings("unchecked")
            Future<Boolean> future = (Future<Boolean>) callableMethod.invoke(
                    compensator.getBean(callableClass), paramValueObj);
            // 更新
            // 执行成功后 更新
            compensatorInfoModel.setRetryEndTime(new Date());
            compensatorInfoModel.setStatus(StatusEnum.SUCCESS_COMPENSATOR.getCode());
            compensatorInfoModel.setSuccessMsg(StatusEnum.SUCCESS_COMPENSATOR.getMsg());
            compensator.successUpdateInfoByMd5Code(compensatorInfoModel);
            return future.get();
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}
